﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;

namespace SPort
{
    public partial class Form1 : Form
    {
        private bool Closing = false;//是否正在关闭串口
        private bool Listening = false;//是否没有执行完invoke相关操作   
        private SerialPortInfo _portsInfo;
        private SerialPort _port;
        private bool _isOpen = false;
        private bool _timeing = false;
        private Thread _thread = null;
        private List<Command> _comds = null;
        private static object _obj = new object();
        private static List<SerialClass> _PortList = new List<SerialClass>();

        public Form1()
        {
            if (_portsInfo == null)
                _portsInfo = new SerialPortInfo();
            if (_port == null)
                _port = new SerialPort();
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;//解决跨线程调用的问题        
            initCommand();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            string[] portNames = SerialPort.GetPortNames();
            if (portNames == null)
            {
                MessageBox.Show("本机没有串口！", "Error");
                return;
            }
            foreach (var item in portNames)
            {
                cbSerial.Items.Add(item);
            }
            cbBaudRate.SelectedIndex = 0;
            cbDatabits.SelectedIndex = 0;
            cbParity.SelectedIndex = 0;
            cbStop.SelectedIndex = 0;
        }


        private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {


            if (Closing) return;
            try
            {
                //设置标记，说明我已经开始处理数据   
                Listening = true;
                var port = sender as SerialPort;
                var buffer = _portsInfo.buffer;
                //先记录下来，避免某种原因，人为的原因，操作几次之间时间长，缓存不一致   
                int len = port.BytesToRead;
                //因为要访问UI资源，所以需要使用invoke方式同步ui
                byte[] buff = new byte[len];
                port.Read(buff, 0, len);
                buffer.AddRange(buff);
                var portName = cbSerial.SelectedItem.ToString();
                Invoke((EventHandler)delegate
                {
                    LogHelper.originalLog(Original(buffer.ToArray()));
                    var recvData = Parsing(_portsInfo);
                    if (!string.IsNullOrEmpty(recvData))
                    {
                        //txtRcv.AppendText($"{DateTime.Now.ToString("HH:mm:ss.ff")}"+recvData + "\n");
                        SqlHelper.Add(recvData);
                    }
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                Listening = false;
            }


        }

        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                if (checkBox1.Checked)
                {
                    MessageBox.Show("请先关闭定时发送");
                    return;
                }
                _isOpen = _port.IsOpen;
                if (_isOpen)
                {
                    Closing = true;
                    while (Listening) Application.DoEvents();
                    _port.Close();
                    _port.Dispose();

                    _isOpen = false;
                    btnSend.Enabled = false;
                    BtnSwitch.Text = "打开串口";

                }
                else
                {
                    InitSerialPort();

                    _port.Open();
                    _isOpen = true;
                    BtnSwitch.Text = "关闭串口";
                    btnSend.Enabled = true;
                    Closing = false;
                }

            }
            catch (Exception ex)
            {
                AgainInitControls();
                MessageBox.Show(ex.Message);
            }

        }


        /// <summary>
        /// 解析接收串口的数据
        /// </summary>
        /// <param name="buff"></param>
        /// <returns></returns>
        public string Parsing(SerialPortInfo partInfo)
        {
            string data = "";
            try
            {
                bool data_catched = false;//缓存记录数据是否捕获到   
                if (partInfo.buffer.Count >= 3)
                {
                    if (partInfo.buffer[0] == 0xAA && partInfo.buffer[1] == 0x55)
                    {
                        //数据长度
                        int len = partInfo.buffer[2];
                        //数据完整判断第一步，长度是否足够   
                        //len是数据段长度,3字节是while行注释的3部分长度  
                        if (partInfo.buffer.Count < len + 3) data_catched = false;//数据不够的时候什么都不做
                        else
                            data_catched = true;
                    }
                    else
                    {
                        //这里是很重要的，如果数据开始不是头，则删除数据
                        partInfo.buffer.RemoveAt(0);
                    }
                }
                //else if (partInfo.buffer[0] == 0x06)
                //    data_catched = true;
                //分析数据
                if (data_catched)
                {
                    foreach (var item in partInfo.buffer)
                    {
                        data += $"{item.ToString("X2")} ";
                    }
                    partInfo.buffer = new List<byte>();

                }
            }
            catch (Exception)
            {
                var str = string.Empty;
                foreach (var item in partInfo.buffer)
                {
                    str += $"{item.ToString("X2")} ";
                }
                LogHelper.Error("数据分析出错：" + str);
            }
            return data;

        }

        /// <summary>
        /// 原始数据
        /// </summary>
        /// <param name="buff"></param>
        /// <param name="partInfo"></param>
        /// <param name="portName"></param>
        /// <returns></returns>
        public string Original(byte[] buff)
        {
            string data = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}：";
            foreach (var item in buff)
            {
                data += $"{item.ToString("X2")} ";
            }
            return data;
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            txtRcv.Text = "";
            txtSend.Text = "";
            lblCollNum.Text = "0";
            lblErrNum.Text = "0";
        }


        private void btnSend_Click(object sender, EventArgs e)
        {

            try
            {

                if (_isOpen)
                {

                    string buff = txtSend.Text;
                    Regex rex = new Regex(@"\s");
                    string sendData = rex.Replace(buff, "");
                    //不发送新行
                    int num = (sendData.Length - sendData.Length % 2) / 2;
                    byte[] temp = new byte[num];
                    for (int i = 0; i < num; i++)
                    {
                        temp[i] = Convert.ToByte(sendData.Substring(i * 2, 2), 16);
                    }
                    _port.Write(temp, 0, num);


                }
            }
            catch (Exception ex)
            {
                AgainInitControls();
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// 初始化串口
        /// </summary>
        private void InitSerialPort()
        {
            var bufLen = 0;
            var name = cbSerial.SelectedItem.ToString();
            var port = new SerialPort();
            port.PortName = name;
            port.BaudRate = Convert.ToInt32(cbBaudRate.Text);
            port.DataBits = Convert.ToInt32(cbDatabits.Text);
            switch (cbParity.Text)
            {
                case "None":
                    port.Parity = Parity.None;
                    break;
                case "Odd":
                    port.Parity = Parity.Odd;
                    break;
                case "Even":
                    port.Parity = Parity.Even;
                    break;
                case "Mark":
                    port.Parity = Parity.Mark;
                    break;
                case "Space":
                    port.Parity = Parity.Space;
                    break;
                default:
                    break;
            }
            port.ReadTimeout = 10000;
            port.WriteTimeout = 10000;
            port.NewLine = "\n";
            port.DataReceived += Port_DataReceived;
            _port = port;
            if (port.BaudRate == 115200) bufLen = 4;
            if (port.BaudRate == 9600) bufLen = 5;
            _portsInfo = new SerialPortInfo { BufMaxLen = bufLen };
        }


        /// <summary>
        /// 重新初始化界面
        /// </summary>
        private void AgainInitControls()
        {
            cbSerial.Items.Clear();
            cbSerial.Items.AddRange(SerialPort.GetPortNames());
            BtnSwitch.Text = "打开串口";
            lblCollNum.Text = "0";
        }


        private void timeingSetComm()
        {
            while (_timeing)
            {
                foreach (var item in _comds)
                {
                    Thread.Sleep(300);
                    _port.Write(item.ComStr, 0, item.ComStr.Length);

                }
            }
        }

        private void initCommand()
        {
            _comds = new List<Command>()
            {
                new Command(){Delay=200,ComStr=new byte[]{ 0xAA,0x55,0x0A,0x00,0x04,0x01,0x03,0x25,0x01,0x62,0x01,0x01,0xB5 } },
                new Command(){Delay=450,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0xAA,0x55,0x0F,0x00,0xF1,0x01, 0x07, 0x25, 0x01, 0x62, 0x03, 0x01, 0x00, 0x02, 0xFE, 0xFE, 0x01, 0x40 } },
                new Command(){Delay=100,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=200,ComStr=new byte[]{ 0xAA,0x55, 0x05, 0x00, 0x13, 0x00, 0x00, 0xE9 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0xAA, 0x55, 0x1E, 0x00, 0xF1, 0x01, 0x16, 0x25, 0x01, 0x80, 0x07, 0x00, 0xB0, 0x10, 0x01, 0x03, 0xDB, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x0C, 0x0B, 0x01, 0xE7 } },
                new Command(){Delay=100,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=200,ComStr=new byte[]{ 0xAA, 0x55, 0x05, 0x00, 0x13, 0x00, 0x00, 0xE9 } },
                new Command(){Delay=13720,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=1000,ComStr=new byte[]{ 0xAA, 0x55, 0x0A, 0x00, 0x04, 0x01, 0x03, 0x25, 0x01, 0x62, 0x01, 0x01, 0xB5 } },
                new Command(){Delay=200,ComStr=new byte[]{ 0xAA, 0x55, 0x0A, 0x00, 0x04, 0x01, 0x03, 0x25, 0x01, 0x62, 0x01, 0x01, 0xB5 } },
                new Command(){Delay=450,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0xAA, 0x55, 0x0F, 0x00, 0xF1, 0x01, 0x07, 0x25, 0x01, 0x62, 0x03, 0x01, 0x00, 0x02, 0xFE, 0xFE, 0x01, 0x40 } },
                new Command(){Delay=100,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=200,ComStr=new byte[]{ 0xAA, 0x55, 0x05, 0x00, 0x13, 0x00, 0x00, 0xE9 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{  0xAA, 0x55, 0x1E, 0x00, 0xF1, 0x01, 0x16, 0x25, 0x01, 0x80, 0x07, 0x00, 0xB0, 0x10, 0x01, 0x03, 0xDB, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x0C, 0x0B, 0x01, 0xE7  } },
                new Command(){Delay=100,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=200,ComStr=new byte[]{ 0xAA, 0x55, 0x05, 0x00, 0x13, 0x00, 0x00, 0xE9 } },
                new Command(){Delay=12720,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=450,ComStr=new byte[]{ 0xAA, 0x55, 0x0A, 0x00, 0x04, 0x01, 0x03, 0x25, 0x01, 0x62, 0x01, 0x01, 0xB5 } },
                new Command(){Delay=50,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0xAA, 0x55, 0x0F, 0x00, 0xF1, 0x01, 0x07, 0x25, 0x01, 0x62, 0x03, 0x01, 0x00, 0x02, 0xFE, 0xFE, 0x01, 0x40 } },
                new Command(){Delay=120,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=80,ComStr=new byte[]{ 0xAA, 0x55, 0x05, 0x00, 0x13, 0x00, 0x00, 0xE9 } },
                new Command(){Delay=14290,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=140,ComStr=new byte[]{ 0xAA, 0x55, 0x0A, 0x00, 0x04, 0x01, 0x03, 0x25, 0x01, 0x62, 0x01, 0x01, 0xB5 } },
                new Command(){Delay=450,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0xAA, 0x55, 0x0F, 0x00, 0xF1, 0x01, 0x07, 0x25, 0x01, 0x62, 0x03, 0x01, 0x00, 0x02, 0xFE, 0xFE, 0x01, 0x40 } },
                new Command(){Delay=220,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=80,ComStr=new byte[]{ 0xAA, 0x55, 0x05, 0x00, 0x13, 0x00, 0x00, 0xE9 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{  0xAA, 0x55, 0x1E, 0x00, 0xF1, 0x01, 0x16, 0x25, 0x01, 0x80, 0x07, 0x00, 0xB0, 0x10, 0x01, 0x03, 0xDB, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x0C, 0x0B, 0x01, 0xE7   } },
                new Command(){Delay=1000,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{  0xAA, 0x55, 0x05, 0x00, 0x13, 0x00, 0x00, 0xE9 } },
                new Command(){Delay=300,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=10,ComStr=new byte[]{ 0xAA, 0x55, 0x1E, 0x00, 0xF1, 0x01, 0x16, 0x25, 0x01, 0x80, 0x07, 0x00, 0xB0, 0x10, 0x01, 0x03, 0xDB, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x0C, 0x0B, 0x01, 0xE7 } },
                new Command(){Delay=550,ComStr=new byte[]{ 0x06 } },
                new Command(){Delay=330,ComStr=new byte[]{ 0xAA, 0x55, 0x05, 0x00, 0x13, 0x00, 0x00, 0xE9 } },
                new Command(){Delay=11880,ComStr=new byte[]{ 0x06 } },
            };
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            //if (sender is CheckBox cb)
            //{
            //    if (cb.Checked)
            //    {
            //        _timeing = true;
            //        _thread = new Thread(timeingSetComm);
            //        _thread.IsBackground = true;
            //        _thread.Start();
            //    }
            //    else
            //    {
            //        _timeing = false;
            //        _thread.Abort();
            //    }
            //}
        }



        private void btnSearch_Click(object sender, EventArgs e)
        {
            _PortList = SqlHelper.GetList(pickerBegTime.Text, pickerEndTime.Text);
            dataGridView1.DataSource = _PortList;

        }

        private void tabPage2_Click(object sender, EventArgs e)
        {

        }

        private void btnAnaly_Click(object sender, EventArgs e)
        {
            try
            {
                var ticks = Convert.ToInt32(txbanalysis.Text) * 10000;

                #region 拆分数据
                var ports = new Dictionary<DateTime, List<string[]>>();
                if (_PortList != null && _PortList.Count > 0)
                {
                    var firstDate = _PortList[0].Date;
                    for (int i = 0, len = _PortList.Count; i < len; i++)
                    {
                        string[] datas = _PortList[i].DataStr.Split(' ');
                        var nextDate = firstDate.AddSeconds(15);
                        var timeSpan = nextDate - _PortList[i].Date;
                        if (timeSpan.Ticks > 0 && timeSpan.Ticks <= ticks)
                        {
                            var a = ports.Keys.Where(x => x == firstDate).FirstOrDefault();
                            if (ports.Keys.Where(x => x == firstDate).FirstOrDefault() != DateTime.MinValue)
                                ports[firstDate].Add(datas);
                            else
                            {
                                ports.Add(firstDate, new List<string[]>());
                                ports[firstDate].Add(datas);
                            }

                        }
                        else
                        {
                            firstDate = _PortList[i].Date;
                            ports.Add(firstDate, new List<string[]>());
                            ports[firstDate].Add(datas);
                        }


                    }
                }

                #endregion

                #region 分析数据
                int corrNum = 0, errorNum = 0;
                var dataList = new List<SerialClass>();
                foreach (var item in ports)
                {
                    var values = item.Value;
                    for (int i = 0; i < values.Count - 1; i++)
                    {
                        var datas = values[i];
                        if (datas.Count() < 3)
                        {
                            errorNum++;
                            dataList.Add(new SerialClass {
                                Date = item.Key,
                                DataStr = string.Join(" ", datas)
                            });
                            continue;
                        }
                        else if (values[i][2] == values[i + 1][2])
                        {
                            values.RemoveAt(i);
                        }
                    }
                    if (values.Count() == 5) corrNum++;
                    else {
                        errorNum++;
                        foreach (var dataStr in values)
                        {
                            var str = string.Join(" ", dataStr);
                            dataList.Add(new SerialClass
                            {
                                Date = item.Key,
                                DataStr = str
                            });
                        }
                    } 
                }

                dataGridView2.DataSource = dataList;

                lblCollNum.Text = corrNum.ToString();
                lblErrNum.Text = errorNum.ToString();
                #endregion

                MessageBox.Show("分析成功");
            }
            catch (Exception ex)
            {
                MessageBox.Show("分析失败：" + ex.Message);
            }
        }
    }
}
 